package com.kevin.learn.leetcode;


import com.kevin.learn.http.HttpGetWithEntity;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.SSLException;



public class HttpClientUtils {
    static Log log = LogFactory.getLog(HttpClientUtils.class);
	private static CloseableHttpClient httpClient;

	static {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(100);
		cm.setDefaultMaxPerRoute(100);
		httpClient = HttpClients.custom().setRetryHandler(createRequestRetryHandler()).setConnectionManager(cm).build();
	}

	private static RequestConfig getRequestConfig() {
		// return
		// RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
		return RequestConfig.custom().setConnectTimeout(120000).setConnectionRequestTimeout(120000)
				.setSocketTimeout(120000).build();
	}

	private static HttpRequestRetryHandler createRequestRetryHandler() {
		return new HttpRequestRetryHandler() {
			@Override
			public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
				if (executionCount > 3) {
					return false;
				}
				if (exception instanceof InterruptedIOException || exception instanceof UnknownHostException
						|| exception instanceof ConnectTimeoutException || exception instanceof SSLException) {
					return false;
				}

				final HttpClientContext clientContext = HttpClientContext.adapt(context);
				final HttpRequest request = clientContext.getRequest();
				boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
				if (idempotent) {
					return true;
				}
				return false;
			}
		};
	}

	/**
	 * 无参get请求
	 *
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String doGet(String url) throws Exception {
		// 创建http GET请求
		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(getRequestConfig());// 设置请求参数
		CloseableHttpResponse response = null;
		try {
			long begin = System.currentTimeMillis();
			// 执行请求
			response = httpClient.execute(httpGet);
			long end = System.currentTimeMillis();
			long timeLength = (end - begin) / 1000;
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			} else {
			    return null;
			}
		} catch (Exception ex) {
			throw ex;
		} finally {
			if (response != null) {
				response.close();
			}
		}
	}

	/**
	 * 有参get请求
	 *
	 * @param url
	 * @return
	 * @throws URISyntaxException
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public static String doGet(String url, Map<String, String> params) throws Exception {
		URIBuilder uriBuilder = new URIBuilder(url);
		if (params != null) {
			for (String key : params.keySet()) {
				uriBuilder.setParameter(key, params.get(key));
			}
		}
		return doGet(uriBuilder.build().toString());
	}

	/**
	 * 有参post请求
	 *
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String doPost(String url, Map<String, String> params) throws Exception {
		// 创建http POST请求
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(getRequestConfig());
		if (params != null) {
			// 设置2个post参数，一个是scope、一个是q
			List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
			for (String key : params.keySet()) {
				parameters.add(new BasicNameValuePair(key, params.get(key)));
			}
			// 构造一个form表单式的实体
			UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
			// 将请求实体设置到httpPost对象中
			httpPost.setEntity(formEntity);
		}
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpClient.execute(httpPost);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} finally {
			if (response != null) {
				response.close();
			}
		}
		return null;
	}

	/**
	 * 有参post请求
	 *
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String doPost(String url, Map<String, String> params, Map<String, String> headerMap)
			throws Exception {
		// 创建http POST请求
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(getRequestConfig());
		
		if(headerMap != null){
			for(Entry<String, String> header: headerMap.entrySet()){
				httpPost.setHeader(header.getKey(), header.getValue());
			}
		}
		
		if (params != null) {
			// 设置2个post参数，一个是scope、一个是q
			List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
			for (String key : params.keySet()) {
				parameters.add(new BasicNameValuePair(key, params.get(key)));
			}
			// 构造一个form表单式的实体
			UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
			// 将请求实体设置到httpPost对象中
			httpPost.setEntity(formEntity);
		}
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpClient.execute(httpPost);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} finally {
			if (response != null) {
				response.close();
			}
		}
		return null;
	}

	/**
	 * 有参post请求
	 *
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String doPostMultipartFile(String url, Map<String, String> params, Map<String, String> headerMap)
			throws Exception {
		// 创建http POST请求
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(getRequestConfig());
		
		if(headerMap != null){
			for(Entry<String, String> header: headerMap.entrySet()){
				httpPost.setHeader(header.getKey(), header.getValue());
			}
		}
		
		if (params != null) {
			// 构造一个form表单式的实体
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();

			for (String key : params.keySet()) {
				builder.addBinaryBody(key, new File(params.get(key)));
			}

			HttpEntity reqEntity = builder.build();

			// 将请求实体设置到httpPost对象中
			httpPost.setEntity(reqEntity);
		}
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpClient.execute(httpPost);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} finally {
			if (response != null) {
				response.close();
			}
		}
		return null;
	}

	/**
	 * 有参post请求,json交互
	 *
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String doPostJson(String url, String json) throws Exception {
		// 创建http POST请求
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(getRequestConfig());
		if (StringUtils.isNotBlank(json)) {
			// 标识出传递的参数是 application/json
			StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
			httpPost.setEntity(stringEntity);
		}
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpClient.execute(httpPost);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} finally {
			if (response != null) {
				response.close();
			}
		}
		return null;
	}

	/**
	 * 无参post请求
	 *
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String doPost(String url) throws Exception {
		return doPost(url, null);
	}


    public static String sendJsonByGetReq(String url, String param) throws Exception {

        String body = "";

        //创建httpclient对象
        CloseableHttpClient client = HttpClients.createDefault();

        HttpGetWithEntity httpGetWithEntity = new HttpGetWithEntity(URI.create(url));
        HttpEntity httpEntity = new StringEntity(param, ContentType.APPLICATION_JSON);
        httpGetWithEntity.setEntity(httpEntity);

        //执行请求操作，并拿到结果（同步阻塞）
        CloseableHttpResponse response = client.execute(httpGetWithEntity);
        //获取结果实体
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            //按指定编码转换结果实体为String类型
            body = EntityUtils.toString(entity, "utf-8");
        }
        //释放链接
        response.close();
        return body;
    }
}